# coding: utf-8
from collections import deque
from typing import Callable, Any, Union

from PySide6.QtCore import QObject, Signal, QThread


class RequestHandler:
    def __init__(self, func: Callable, slot: Callable = None, *args, **kwargs):
        self.func = func
        self.slot = slot
        self.args = args
        self.kwargs = kwargs


class ResponseHandler:
    def __init__(self, slot: Callable, result: Any = None, error: Union[Exception, str] = None):
        self.slot = slot
        self.result = result
        if isinstance(error, Exception):
            error = str(error)
        elif error is None:
            error = ""
        self.error = error


class EventSignalBus(QObject):
    fetchDataSignal = Signal(RequestHandler)
    resultSignal = Signal(ResponseHandler)


class QueueThread(QThread):
    result = Signal(ResponseHandler)
    failed = Signal(object)  # 返回失败信息信号

    def __init__(self, parent=None):
        super().__init__(parent)
        self.tasks = deque()

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def taskDone(self):
        pass

    def handleTask(self, task: RequestHandler):
        result = task.func(*task.args, **task.kwargs)
        return result

    def handleTaskError(self, task: RequestHandler, error: Exception):
        pass

    def run(self):
        self.setUp()
        while self.tasks:
            task = self.tasks.popleft()
            try:
                result = self.handleTask(task)
                error = None
            except Exception as e:
                result = None
                error = str(e)
                self.handleTaskError(task, e)
                self.failed.emit(error)
            self.result.emit(ResponseHandler(task.slot, result=result, error=error))
            self.taskDone()
        self.tearDown()

    def addTask(self, task: RequestHandler):
        self.tasks.append(task)
        if not self.isRunning():
            self.start()
